package evq.codec.core.converters;

import java.util.ArrayList;
import java.util.List;

import evq.codec.core.entities.Pgm;
import evq.codec.core.entities.Vector;

public class Converter {

	public static List<Vector> convertPgmToVectors(Pgm pgm, int quantizatorDimension) {

		//Get the pixels Matrix
		List<List<Integer>> pixelsMatrix = new ArrayList<List<Integer>>(pgm.getImage());

		//Get the number of blocks to be iterated
		int lineOfBlocks = (int) (pgm.getHeight()/Math.sqrt(quantizatorDimension));

		//Initializing the set of the vectors that will be returned
		List<Vector> vectors = new ArrayList<Vector>();

		//Iterating over the blocks to get the vectors that will represent the image that will be quantized
		for(int i = 1; i <= lineOfBlocks; i++){
			for(int blockNumber = 0; blockNumber < lineOfBlocks; blockNumber++){

				//Creating the block and adding it to set of vectors that will be represent the image
				readBlock(pixelsMatrix,vectors,(int) Math.sqrt(quantizatorDimension),blockNumber);
				//Deleting the block read of the pixelsMatrix.
				deleteBlock(pixelsMatrix,(int) Math.sqrt(quantizatorDimension),blockNumber);
			}
		}

		return vectors;

	}

	public static Pgm convertVectorsToPgm(List<Vector> vectors,int width,int height,int grayScale) {

		//Initialize parameters to conversion
		int quantizatorDimension = vectors.get(0).size();
		int lineOfBlocks = (int)(height/Math.sqrt(quantizatorDimension));
		//Initialize the matrix of pixels that will be filled
		List<List<Integer>> pixelsMatrix = initializePixelsMatrix(height);

		//Iterating over the groups of 16 lines of the pixels matrix.
		for(int multiplicityValue = 1; multiplicityValue <= lineOfBlocks; multiplicityValue++){
			
			//Initializing the parameters of the columns of the block. 
			int columnNumber = (int)((multiplicityValue-1)*Math.sqrt(quantizatorDimension));
			int columnLimit = (int)((multiplicityValue * Math.sqrt(quantizatorDimension)));
			
			//Iterating over the blocks into the group.
			for(int i = 1; i <= lineOfBlocks; i++){

				//Initializing the parameters that will control the number of the write block 
				int lineNumber = (int)(((i-1)*Math.sqrt(quantizatorDimension)));
				int lineLimit = (int)((i*Math.sqrt(quantizatorDimension)));	

				//Iterating over the blocks of 16 columns.
				for(int blockNumber = lineNumber; blockNumber < lineLimit; blockNumber++){
					writeBlock(pixelsMatrix, vectors.get(0), (int) Math.sqrt(quantizatorDimension), blockNumber, columnNumber, columnLimit);
				}
				vectors.remove(0);
			}
	}

	//Setting the parameters of the pgm object.
	Pgm pgm = new Pgm();
	pgm.setGrayScale(grayScale);
	pgm.setHeight(height);
	pgm.setWidth(width);
	//Setting the pixels matrix in the pgm object.
	pgm.setImage(pixelsMatrix);

	return pgm;
}

private static void readBlock(List<List<Integer>> pixelsMatrix,List<Vector> vectors, int quantizatorDimension,int blockNumber){

	//Initializing the Vector that will be represent the block of the image that will be quantized
	Vector vector = new Vector();
	//Iterating over the pixels matrix to get the block specified in the method parameter
	for(int lineOfBlock = (blockNumber * quantizatorDimension); lineOfBlock < ((blockNumber+1)*quantizatorDimension); lineOfBlock++){

		for(int columnOfBlock = 0; columnOfBlock < quantizatorDimension; columnOfBlock++){
			double element = pixelsMatrix.get(lineOfBlock).get(columnOfBlock);
			vector.addElement(element);
		}
	}
	vectors.add(vector);

}

private static void deleteBlock(List<List<Integer>> pixelsMatrix, int quantizatorDimension, int blockNumber){

	//Iterating over the block of the pixelsMatrix to remove the elements read.
	for(int lineOfBlock = (blockNumber * quantizatorDimension); lineOfBlock < (blockNumber+1)*quantizatorDimension; lineOfBlock++){
		for(int columnOfBlock = 0; columnOfBlock < quantizatorDimension; columnOfBlock++){
			pixelsMatrix.get(lineOfBlock).remove(0);
		}
	}
}

private static void writeBlock(List<List<Integer>> pixelsMatrix,Vector block, int quantizatorDimension,int blockNumber,int columnNumber, int columnLimit){


	for(int columnOfBlock = columnNumber ; columnOfBlock < columnLimit; columnOfBlock++){
		int element = (int)Math.round(block.getElement(0));
		pixelsMatrix.get(blockNumber).add(columnOfBlock, element);
		block.removeElement(0);
	}
}

private static List<List<Integer>> initializePixelsMatrix(int height){

	List<List<Integer>> pixelsMatrix = new ArrayList<List<Integer>>();

	for(int i = 0; i < height; i++){

		List<Integer> line = new ArrayList<Integer>();
		pixelsMatrix.add(line);
	}

	return pixelsMatrix;
}

}
